package tk.sunlatus.project.security.key;

import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.Security;

import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;
import org.springframework.util.Assert;

import tk.sunlatus.project.common.constants.SunlatusConstants;
import tk.sunlatus.project.usermanage.service.UserService;

/**
 * KeyManager
 * 
 * @creator 悠忧虫
 * @create-time 2011-6-18 下午12:16:25
 * @revision 1.0
 */
public class KeyManager {

    private UserService userService = null;

    public static Key getKey(String keyAlgorithm, int keyLength) {
        Security.addProvider(new BouncyCastleProvider());
        KeyGenerator kGenerator = null;
        try {
            kGenerator = KeyGenerator.getInstance(keyAlgorithm);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        kGenerator.init(keyLength);
        return kGenerator.generateKey();
    }

    public static Key bytesToKey(byte[] keyByte) {
        return bytesToKey(keyByte, false);
    }

    public static Key bytesToKey(byte[] keyByte, boolean needDecode) {
        Key key = null;
        byte[] keyTemp = new byte[keyByte.length];
        System.arraycopy(keyByte, 0, keyTemp, 0, keyByte.length);
        if (needDecode) {
            keyTemp = Hex.decode(keyByte);
        }
        key = new SecretKeySpec(keyTemp, SunlatusConstants.EncodeConstant.KEY_IDEA);
        return key;
    }

    /**
     * 将字符串转换成密钥
     * 
     * @param keyStr
     * @return
     */
    public static Key stringToKey(String keyStr) {
        return stringToKey(keyStr, true);
    }

    private static Key stringToKey(String keyStr, boolean needDecode) {
        byte[] keyByte = needDecode ? Hex.decode(keyStr.getBytes(SunlatusConstants.EncodeConstant.CHARSET)) : keyStr
            .getBytes(SunlatusConstants.EncodeConstant.CHARSET);
        return bytesToKey(keyByte);
    }

    public String keyToString(Key key) {

        Assert.notNull(key);
        return hexEncode(key.getEncoded());
    }

    /**
     * 根据用户ID、是否为信息摘要获取salt信息
     * 
     * @param userID
     *            用户ID
     * @param digestFlag
     *            是否为信息摘要，true：信息摘要salt，false：加密salt；
     * @return slat 信息
     */
    public String getSalt(String userID, boolean digestFlag) {
        // TODO 获取用户的salt信息
        String salt = null;
        if (digestFlag) {
            salt = "digest";
            // TODO get salt from dataBase
            return hexDecode(salt);
        }
        return null;
    }

    /**
     * 为信息摘要生成salt
     * 
     * @param userID
     * @return
     */
    public byte[] generateSalt4Digest(String userID) {
        // TODO 生成盐
        return hexEncode(userID);
    }

    /**
     * 十六进制编码
     * 
     * @param message
     * @return
     */
    private byte[] hexEncode(String message) {
        return Hex.encode(message.getBytes(SunlatusConstants.EncodeConstant.CHARSET));
    }

    /**
     * 十六进制编码
     * 
     * @param message
     * @return
     */
    private String hexEncode(byte[] message) {
        return new String(Hex.encode(message), SunlatusConstants.EncodeConstant.CHARSET);
    }

    /**
     * 十六进制解码
     * 
     * @param message
     * @return
     */
    private String hexDecode(String message) {
        return new String(Hex.decode(message.getBytes(SunlatusConstants.EncodeConstant.CHARSET)),
            SunlatusConstants.EncodeConstant.CHARSET);
    }

    /**
     * 方法描述：生成以keysalt加密的key
     * 
     * @param keySalt
     * @return
     */
    public static String mixKeyAndSalt(String keyAlgorithm, int length, String keySalt) {
        return mixKeyAndSalt(getKey(keyAlgorithm, length), keySalt);
    }

    /**
     * 方法描述：对密钥进行加密
     * 
     * @param keySalt
     * @return
     */
    public static String mixKeyAndSalt(String keyStr, String keySalt) {

        byte[] keyByte = keyStr.getBytes(SunlatusConstants.EncodeConstant.CHARSET);
        byte[] saltByte = Hex.encode(keySalt.getBytes(SunlatusConstants.EncodeConstant.CHARSET));
        xor(keyByte, saltByte);

        return new String(Hex.encode(keyByte), SunlatusConstants.EncodeConstant.CHARSET);
    }

    /**
     * 方法描述：对密钥进行加密
     * 
     * @param keySalt
     * @return
     */
    public static String mixKeyAndSalt(Key key, String keySalt) {

        return mixKeyAndSalt(key.getEncoded(), keySalt);
    }

    /**
     * 方法描述：对密钥进行加密
     * 
     * @param keySalt
     * @return
     */
    public static String mixKeyAndSalt(byte[] keyBytes, String keySalt) {

        return mixKeyAndSalt(new String(keyBytes, SunlatusConstants.EncodeConstant.CHARSET), keySalt);
    }

    /**
     * 方法描述：生成以keysalt加密的key
     * 
     * @param keySalt
     * @return
     */
    public static String unmixKeyAndSalt(String keyStr, String keySalt) {

        byte[] keyByte = Hex.decode(keyStr.getBytes(SunlatusConstants.EncodeConstant.CHARSET));
        byte[] saltByte = Hex.encode(keySalt.getBytes(SunlatusConstants.EncodeConstant.CHARSET));
        xor(keyByte, saltByte);
        return new String(keyByte, SunlatusConstants.EncodeConstant.CHARSET);
    }

    private static void xor(byte[] src, byte[] salt) {
        int mixLength = src.length > salt.length ? salt.length : src.length;
        int cycle = src.length % mixLength == 0 ? src.length / mixLength : (src.length / mixLength) + 1;
        for (int i = 0; i < cycle; i++) {
            for (int j = 0; j < mixLength; j++) {
                if (i * mixLength + j < src.length)
                    src[i * mixLength + j] = (byte) (src[i * mixLength + j] ^ salt[j]);
            }
        }

    }

    public UserService getUserService() {
        return userService;
    }

    public void setUserService(UserService userService) {
        this.userService = userService;
    }
}
